package com.zoo.util;

import com.jz.bean.AppInfoBean;
import com.jz.bean.SynchronizedAppConfigBean;
import com.jz.bean.SynchronizedMainConfigBean;
import com.jz.socket.HeartBeatServerThread;
import com.jz.socket.UDPSocketClient;
import com.jz.util.AttributeSupport;
import com.jz.util.JAXBUtils;
import com.jz.util.TimeUtil;
import com.zoo.MainService;
import com.zoo.curator.AbstractCurator;
import com.zoo.curator.impl.ConcurrentCurator;
import com.zoo.curator.impl.MasterCurator;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.log4j.PropertyConfigurator;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by Administrator on 2015/10/29.
 */
public class CuratorSupport {
    public static final Logger LOGGER = LoggerFactory.getLogger(CuratorSupport.class);
    public static AbstractCurator curator = null;
    private static UDPSocketClient updSocketClient = null;
    private static HeartBeatServerThread hbServer = null;
    public static AppInfoBean localAppInfo = null;

    public static void main(String[] args) {
        PropertyConfigurator.configure(System.getProperty("user.dir")
                + "/config/log4j.properties");
        init();
    }


    public static void init() {
        try {
            LOGGER.error("启动服务端心跳线程");
            hbServer = new HeartBeatServerThread(AttributeSupport.HEARTBEAT_IP, AttributeSupport.HEARTBEAT_PORT) {
                @Override
                public void handle() {
                    handleStatus();
                }

                @Override
                public void initError() {
                    exitAll();
                }
            };
            LOGGER.error("启动UDP广播线程");
            updSocketClient = new UDPSocketClient(AttributeSupport.UDP_HOST, AttributeSupport.UDP_PORT, AttributeSupport.SEND_INTERVAL) {
                @Override
                public byte[] getPushValue() {
                    return getLocalAppNodeValue();
                }
            };
            LOGGER.error("启动ZK监控");
            curator = (AbstractCurator) MainService.springContext.getBean("curator");
            new Thread(curator).start();
        } catch (Exception e) {
            LOGGER.error("", e);
            exitAll();
        }
    }

    /**
     * CHILD进程与ZK服务的心跳连接已断开,
     * 可能是CHILD的进程已经异常退出,
     * 需要通知系统,更新节点状态,判断是否需要重新选举
     */
    private static void handleStatus() {
        LOGGER.info("server:The connection between server and client is lost");
        if (CuratorSupport.curator != null) {
            CuratorSupport.curator.updateAppNodeValue(new AppInfoBean(false, TimeUtil.getTime(), "CHILD stop"));
            if (CuratorSupport.curator.getLeaderSelector() != null) {
                CuratorSupport.curator.getLeaderSelector().releaseWithProcess();
            }
        }
    }

    /**
     * 关闭所有
     */
    public static void exitAll() {
        try {
            if (hbServer != null) {
                hbServer.close();
                LOGGER.error("关闭服务端心跳线程");
            }
            if (updSocketClient != null) {
                updSocketClient.close();
                LOGGER.error("关闭UDP广播线程");
            }
            if (curator != null) {
                curator.close();
                LOGGER.error("关闭ZK监控");
            }
        } catch (Exception e) {
            LOGGER.error("", e);
        } finally {
            System.exit(1);
        }
    }

    /**
     * 建立ZK客户端
     */
    public static CuratorFramework newClient() {
        try {
            ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(AttributeSupport.ZK_TIMEOUT, 3);
            return CuratorFrameworkFactory.newClient(AttributeSupport.HOST_PORT, retryPolicy);
        } catch (Exception e) {
            LOGGER.error("初始化CLIENT异常", e);
        }
        return null;
    }

    /**
     * 更新APP_NODE节点的数据
     * */
//    public static void updateAppNodeValue(AppInfoBean bean){
//        if(isNodeExists(curator.getClient(),APP_NODE)){
//
//        }
//    }

    /**
     * 判断节点是否存在
     */
    public static boolean isNodeExists(CuratorFramework client, String PATH) {
        Stat stat = null;
        try {
            stat = client.checkExists().forPath(PATH);
        } catch (Exception e) {
            stat = null;
            LOGGER.error("判断节点是否存在异常,(" + PATH + ")", e);
        }
        return stat != null;
    }

    /**
     * 建立节点
     */
    public static void createNode(CuratorFramework client, String PATH, CreateMode mode, byte[] value) {
        try {
            if (!isNodeExists(client, PATH)) {
                if (value == null) {
                    client.create().creatingParentsIfNeeded().withMode(mode).forPath(PATH);
                } else {
                    client.create().creatingParentsIfNeeded().withMode(mode).forPath(PATH, value);
                }
            }
        } catch (Exception e) {
            LOGGER.error("新建节点异常,(" + PATH + ")", e);
        }
    }

    /**
     * 更新节点数据
     */
    public static void updateNodeValue(CuratorFramework client, String PATH, byte[] value) {
        try {
            if (isNodeExists(client, PATH)) {
                client.setData().forPath(PATH, value);
            }
        } catch (Exception e) {
            LOGGER.error("更新节点数据异常,(" + PATH + ")", e);
        }
    }

    /**
     * 删除节点
     */
    public static boolean deleteNode(CuratorFramework client, String PATH) {
        boolean success = false;
        try {
            if (isNodeExists(client, PATH)) {
                client.delete().deletingChildrenIfNeeded().forPath(PATH);
                success = client.checkExists().forPath(PATH) == null;
            } else {
                success = true;
            }
        } catch (Exception e) {
            success = false;
            LOGGER.error("删除节点异常,(" + PATH + ")", e);
        }
        return success;
    }

    /**
     * 获得节点数据
     */
    public static byte[] getNodeValue(CuratorFramework client, String PATH) {
        byte[] value = null;
        try {
            if (isNodeExists(client, PATH)) {
                value = client.getData().watched().forPath(PATH);
            }
        } catch (Exception e) {
            value = null;
            LOGGER.error("获得节点数据异常,(" + PATH + ")", e);
        }
        return value;
    }

    public static byte[] getAppNodeValue() {
        byte[] data = null;
        try {
            data = getNodeValue(curator.getClient(), AttributeSupport.APP_NODE);
        } catch (Exception e) {
            LOGGER.error("", e);
        }
        return data;
    }

    public static byte[] getLocalAppNodeValue() {
        byte[] data = null;
        try {
            localAppInfo.setUpdateTime(TimeUtil.getTime());
            data = JAXBUtils.dtoToXmlString(localAppInfo).getBytes();
        } catch (Exception e) {
            LOGGER.error("", e);
        }
        return data;
    }

    public static String getMainNodeInitValue() {
        String result = "";
        SynchronizedMainConfigBean et = new SynchronizedMainConfigBean();
        et.setContent("init content");
        et.setUpdateTime(TimeUtil.getTime());
        try {
            result = JAXBUtils.dtoToXmlString(et);
        } catch (Exception e) {
            LOGGER.error("", e);
            result = "";
        }
        return result;
    }

    public static String getAppNodeInitValue() {
        String result = "";
        try {
            result = JAXBUtils.dtoToXmlString(new SynchronizedAppConfigBean());
        } catch (Exception e) {
            LOGGER.error("", e);
            result = "";
        }
        return result;
    }

    public static void changeAppStatus(AppInfoBean info) {
        if (localAppInfo == null) return;
        if (info.getLocalIP().equals(localAppInfo.getLocalIP())) {
            if (localAppInfo.isChildRun()) {
                curator.killProcess(null);
            } else {
                curator.startProcess(null);
            }
        }
    }
}
